import {openWindow} from './window';

interface DownloadOptions<T = string> {
    fileName?: string;
    source: T;
    target?: string;
}

const DEFAULT_FILENAME = 'downloaded_file';

/**
 * 通过 URL 下载文件，支持跨域
 * @throws {Error} - 当下载失败时抛出错误
 */
export async function downloadFileFromUrl({
                                              fileName,
                                              source,
                                              target = '_blank',
                                          }: DownloadOptions): Promise<void> {
    if (!source || typeof source !== 'string') {
        throw new Error('Invalid URL.');
    }

    const isChrome = window.navigator.userAgent.toLowerCase().includes('chrome');
    const isSafari = window.navigator.userAgent.toLowerCase().includes('safari');

    if (/iP/.test(window.navigator.userAgent)) {
        console.error('Your browser does not support download!');
        return;
    }

    if (isChrome || isSafari) {
        triggerDownload(source, resolveFileName(source, fileName));
        return;
    }
    if (!source.includes('?')) {
        source += '?download';
    }

    openWindow(source, {target});
}

/**
 * 通过 Base64 下载文件
 */
export function downloadFileFromBase64({fileName, source}: DownloadOptions) {
    if (!source || typeof source !== 'string') {
        throw new Error('Invalid Base64 data.');
    }

    const resolvedFileName = fileName || DEFAULT_FILENAME;
    triggerDownload(source, resolvedFileName);
}

/**
 * 通过图片 URL 下载图片文件
 */
export async function downloadFileFromImageUrl({
                                                   fileName,
                                                   source,
                                               }: DownloadOptions) {
    const base64 = await urlToBase64(source);
    downloadFileFromBase64({fileName, source: base64});
}

/**
 * 通过 Blob 下载文件
 */
export function downloadFileFromBlob({
                                         fileName = DEFAULT_FILENAME,
                                         source,
                                     }: DownloadOptions<Blob>): void {
    if (!(source instanceof Blob)) {
        throw new TypeError('Invalid Blob data.');
    }

    const url = URL.createObjectURL(source);
    triggerDownload(url, fileName);
}

/**
 * 下载文件，支持 Blob、字符串和其他 BlobPart 类型
 */
export function downloadFileFromBlobPart({
                                             fileName = DEFAULT_FILENAME,
                                             source,
                                         }: DownloadOptions<BlobPart>): void {
    // 如果 data 不是 Blob，则转换为 Blob
    const blob =
        source instanceof Blob
            ? source
            : new Blob([source], {type: 'application/octet-stream'});

    // 创建对象 URL 并触发下载
    const url = URL.createObjectURL(blob);
    triggerDownload(url, fileName);
}

/**
 * img url to base64
 * @param url
 */
export function urlToBase64(url: string, mineType?: string): Promise<string> {
    return new Promise((resolve, reject) => {
        let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null;
        const ctx = canvas?.getContext('2d');
        const img = new Image();
        img.crossOrigin = '';
        img.addEventListener('load', () => {
            if (!canvas || !ctx) {
                return reject(new Error('Failed to create canvas.'));
            }
            canvas.height = img.height;
            canvas.width = img.width;
            ctx.drawImage(img, 0, 0);
            const dataURL = canvas.toDataURL(mineType || 'image/png');
            canvas = null;
            resolve(dataURL);
        });
        img.src = url;
    });
}

/**
 * 通用下载触发函数
 * @param href - 文件下载的 URL
 * @param fileName - 下载文件的名称，如果未提供则自动识别
 * @param revokeDelay - 清理 URL 的延迟时间 (毫秒)
 */
export function triggerDownload(
    href: string,
    fileName: string | undefined,
    revokeDelay: number = 100,
): void {
    const defaultFileName = 'downloaded_file';
    const finalFileName = fileName || defaultFileName;

    const link = document.createElement('a');
    link.href = href;
    link.download = finalFileName;
    link.style.display = 'none';

    if (link.download === undefined) {
        link.setAttribute('target', '_blank');
    }

    document.body.append(link);
    link.click();
    link.remove();

    // 清理临时 URL 以释放内存
    setTimeout(() => URL.revokeObjectURL(href), revokeDelay);
}

function resolveFileName(url: string, fileName?: string): string {
    return fileName || url.slice(url.lastIndexOf('/') + 1) || DEFAULT_FILENAME;
}
